/***************************************************************************
 *   Copyleft 2006-2007 by												   *
 *	 Iwanicki Krzysztof													   *
 *   <gamma.mini.pw.edu.pl/~iwanickik>									   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 ***************************************************************************/
#include "./TriGregory.h"

/**************************************************************
* Constructors                                                *
***************************************************************/
TriGregory::TriGregory(BezierSurface *p1, BezierSurface *p2, BezierSurface *p3) : Object3D() {
	mMeshVisible = false;
	mPointsVisible = false;
	mBezierPrecision = 5;
	mGregoryPrecision = 7;
	mCurveParam = 0.5f;
	mContinuity = 0;

	mBezierSurfaces[0] = p1;
	mBezierSurfaces[1] = p2;
	mBezierSurfaces[2] = p3;

	for (cInt i = 0; i < 3; i++)	{
		mGregorySurfaces[i] = cNull;
		mBezierCurves[i] = cNull;
	}

	for (cInt k = 0; k < 3; k++)	{
		mOldSurfaces[k] = DynamicArray2D<Point4D>(4, 4);
		for (cInt i = 0; i < 4; i++) {
			for (cInt j = 0; j < 4; j++) {
				mOldSurfaces[k](i, j) = mBezierSurfaces[k]->GetMeshPoint(i, j);
			}
		}
	}

	FillGregory();
}

TriGregory::~TriGregory() {
	for (cInt i = 0; i < 3; i++)	{
		delete mBezierSurfaces[i];
		delete mBezierCurves[i];
		delete mGregorySurfaces[i];
	}
}

    
/**************************************************************
* Operators                                                   *
***************************************************************/


/**************************************************************
* Other helpful functions                                     *
***************************************************************/
cVoid TriGregory::SetMeshVisible(cBool v) {
	mMeshVisible = v;
	for (cInt i = 0; i < 3; i++)	{
		mBezierSurfaces[i]->SwitchControlPointsVisibility();
		mBezierSurfaces[i]->SwitchMeshVisibility();
		mGregorySurfaces[i]->SwitchMeshVisibility();
	}
}

cBool TriGregory::GetMeshVisible() {
	return mMeshVisible;
}

cVoid TriGregory::SetPointsVisible(cBool v) {
	//mPointsVisible = v;
	for (cInt i = 0; i < 3; i++) {
		//mBezierCurves[i]->SwitchPointsVisibility();
	}
}

cBool TriGregory::GetPointsVisible() {
	return mPointsVisible;
}

cVoid TriGregory::SetBezierPrecision(cInt prec) {
	if (prec <= 1) {
		return;
	}
	mBezierPrecision = prec;
	for (cInt i = 0; i < 3; i++) {
		mBezierSurfaces[i]->ChangeU(prec - mBezierPrecision);
		mBezierSurfaces[i]->ChangeV(prec - mBezierPrecision);
	}
}

cInt TriGregory::GetBezierPrecision() {
	return mBezierPrecision;
}

cVoid TriGregory::SetGregoryPrecision(cInt prec) {
	if (prec <= 1) {
		return;
	}
	
	for (cInt i = 0; i < 3; i++) {
		mGregorySurfaces[i]->ChangeU(prec - mGregoryPrecision);
		mGregorySurfaces[i]->ChangeV(prec - mGregoryPrecision);
	}
	mGregoryPrecision = prec;
}

cInt TriGregory::GetGregoryPrecision() {
	return mGregoryPrecision;
}

cVoid TriGregory::SetCurveParam(cFloat param) {
	mCurveParam = param;
	FillGregory();
}

cFloat TriGregory::GetCurveParam() {
	return mCurveParam;
}

cVoid TriGregory::ToggleContinuity() {
	mContinuity = (mContinuity + 1) % 3;
	FillGregory();
}

/*virtual*/ cVoid TriGregory::Render(Renderer& renderer, Matrix4D& matrix, ProjectionPlane& plane) {
	cInt iHalfWidth = renderer.GetWidth() >> 1, iHalfHeight = renderer.GetHeight() >> 1;
	for (cInt i = 0; i < 3; i++) {
		if (mBezierSurfaces[i] != cNull) {
			mBezierSurfaces[i]->Render(renderer, matrix, plane);
		}
		if (mBezierCurves[i] != cNull) {
			mBezierCurves[i]->Render(renderer, matrix, plane);
		}
		if (mGregorySurfaces[i] != cNull) {
			mGregorySurfaces[i]->Render(renderer, matrix, plane);
		}
	}
	Point4D p, pp;
	if (mMeshVisible) {
		// drawing c1 mGregorySurfaces's help lines
		for (cInt k = 0; k < 3; k++) {
			if (mGregorySurfaces[k] == cNull) {
				continue;
			}
			for (cInt i = 0; i < 2; i++) {
				for (cInt j = 0; j < 2; j++) {
					p = matrix * mGregorySurfaces[k]->Puv[i][j];
					pp = matrix * mGregorySurfaces[k]->Pv[i][j];
					renderer.DrawROPLine((cInt) p.mX + iHalfWidth, (cInt) -p.mY + iHalfHeight, 
						(cInt) pp.mX + iHalfWidth, (cInt) -pp.mY + iHalfHeight, mColor);

					p = matrix * mGregorySurfaces[k]->Pvu[i][j];
					pp = matrix * mGregorySurfaces[k]->Pu[i][j];
					renderer.DrawROPLine((cInt) p.mX + iHalfWidth, (cInt) -p.mY + iHalfHeight, 
						(cInt) pp.mX + iHalfWidth, (cInt) -pp.mY + iHalfHeight, mColor);
				}
			}
		}
	}

	if (mPointsVisible) {
		// drawing mMidSurfaces control points
		for (cInt k = 0; k < 3; k++) {
			for (cInt i = 0; i < mMidSurfaces[k].GetRowSize(); i++) {
				for (cInt j = 0; j < mMidSurfaces[k].GetColSize(); j++) {
					p = matrix * mMidSurfaces[k](i, j);
					p.mX += iHalfWidth;
					p.mY = -p.mY + iHalfHeight;
					renderer.DrawPoint(p, mColor, (cShort) 0);
				}
			}
		}
	}
}
/*virtual*/ cVoid TriGregory::Render(Renderer& renderer, Matrix4D& matrix, ProjectionPlane& plane, cWinColor color) {
	cInt iHalfWidth = renderer.GetWidth() >> 1, iHalfHeight = renderer.GetHeight() >> 1;
	for (cInt i = 0; i < 3; i++) {
		if (mBezierSurfaces[i] != cNull) {
			mBezierSurfaces[i]->Render(renderer, matrix, plane, color);
		}
		if (mBezierCurves[i] != cNull) {
			mBezierCurves[i]->Render(renderer, matrix, plane, color);
		}
		if (mGregorySurfaces[i] != cNull) {
			mGregorySurfaces[i]->Render(renderer, matrix, plane, color);
		}
	}
	Point4D p, pp;
	if (mMeshVisible) {
		// drawing c1 mGregorySurfaces's help lines
		for (cInt k = 0; k < 3; k++) {
			if (mGregorySurfaces[k] == cNull) {
				continue;
			}
			for (cInt i = 0; i < 2; i++) {
				for (cInt j = 0; j < 2; j++) {
					p = matrix * mGregorySurfaces[k]->Puv[i][j];
					pp = matrix * mGregorySurfaces[k]->Pv[i][j];
					renderer.DrawROPLine((cInt) p.mX + iHalfWidth, (cInt) -p.mY + iHalfHeight, 
						(cInt) pp.mX + iHalfWidth, (cInt) -pp.mY + iHalfHeight, color);

					p = matrix * mGregorySurfaces[k]->Pvu[i][j];
					pp = matrix * mGregorySurfaces[k]->Pu[i][j];
					renderer.DrawROPLine((cInt) p.mX + iHalfWidth, (cInt) -p.mY + iHalfHeight, 
						(cInt) pp.mX + iHalfWidth, (cInt) -pp.mY + iHalfHeight, color);
				}
			}
		}
	}

	if (mPointsVisible) {
		// drawing mMidSurfaces control points
		for (cInt k = 0; k < 3; k++) {
			for (cInt i = 0; i < mMidSurfaces[k].GetRowSize(); i++) {
				for (cInt j = 0; j < mMidSurfaces[k].GetColSize(); j++) {
					p = matrix * mMidSurfaces[k](i, j);
					p.mX += iHalfWidth;
					p.mY = -p.mY + iHalfHeight;
					renderer.DrawPoint(p, color, (cShort) 1);
				}
			}
		}
	}
}

/*virtual*/ cVoid TriGregory::DisplayInfo(Renderer& renderer) {
	cChar pcBuff [MAX_BUF_SIZE];
	cInt iLineNr = 0;

	sprintf_s(pcBuff, "Triangular Gregory Hole Filling Info:");
	renderer.DrawString(H_TXT_SPACER, iLineNr++ * V_TXT_SPACER, pcBuff, 
		true, true, true, RGB(0, 255, 255));
	sprintf_s(pcBuff, "Continuity : ");	
	renderer.DrawString(H_TXT_SPACER, iLineNr * V_TXT_SPACER, pcBuff, 
		false, true, true, Color::ToWinColor(WHITE));
	sprintf_s(pcBuff, "C%i", mContinuity);	
	renderer.DrawString(H_TXT_SPACER * 13, iLineNr++ * V_TXT_SPACER, pcBuff, 
		true, true, true, Color::ToWinColor(WHITE));
	sprintf_s(pcBuff, "U : ");	
	renderer.DrawString(H_TXT_SPACER, iLineNr * V_TXT_SPACER, pcBuff, 
		false, true, true, Color::ToWinColor(WHITE));
	sprintf_s(pcBuff, "%3i", mGregoryPrecision);	
	renderer.DrawString(H_TXT_SPACER * 3, iLineNr++ * V_TXT_SPACER, pcBuff, 
		true, true, true, Color::ToWinColor(WHITE));
	sprintf_s(pcBuff, "V : ");	
	renderer.DrawString(H_TXT_SPACER, iLineNr * V_TXT_SPACER, pcBuff, 
		false, true, true, Color::ToWinColor(WHITE));
	sprintf_s(pcBuff, "%3i", mGregoryPrecision);	
	renderer.DrawString(H_TXT_SPACER * 3, iLineNr++ * V_TXT_SPACER, pcBuff, 
		true, true, true, Color::ToWinColor(WHITE));
	iLineNr++;
	sprintf_s(pcBuff, "[Ctrl/Alt + J] - Increase/Decrease U/V");
	renderer.DrawString(H_TXT_SPACER, iLineNr++ * V_TXT_SPACER, pcBuff, 
		false, true, true, Color::ToWinColor(WHITE));
	sprintf_s(pcBuff, "[Ctrl/Alt + K] - Increase/Decrease Curve Param");
	renderer.DrawString(H_TXT_SPACER, iLineNr++ * V_TXT_SPACER, pcBuff, 
		false, true, true, Color::ToWinColor(WHITE));
	sprintf_s(pcBuff, "[Ctrl + B] - Show/Hide Control Points");
	renderer.DrawString(H_TXT_SPACER, iLineNr++ * V_TXT_SPACER, pcBuff, 
		false, true, true, Color::ToWinColor(WHITE));
	sprintf_s(pcBuff, "[Ctrl + V] - Show/Hide Mesh");
	renderer.DrawString(H_TXT_SPACER, iLineNr++ * V_TXT_SPACER, pcBuff, 
		false, true, true, Color::ToWinColor(WHITE));
	sprintf_s(pcBuff, "[Ctrl + C] - Switch Continuity");
	renderer.DrawString(H_TXT_SPACER, iLineNr++ * V_TXT_SPACER, pcBuff, 
		false, true, true, Color::ToWinColor(WHITE));
}
/*virtual*/ cChar* TriGregory::GetName() {
	return "TriGregory";
}

cVoid TriGregory::FillGregory() {
	GregorySurface *g;
	Point4D p;

	for (cInt i = 0; i < 3; i++) {
		delete mGregorySurfaces[i];
	}

	CorrectPatches();
	for (cInt i = 0; i < 3; i++) {
		MakeMidPatch(mBezierSurfaces[i], mMidSurfaces[i]);
	}
	MakeBorderCurves();

	// first mGregorySurfaces patch
	g = new GregorySurface();
	g->P[0][1] = mMidSurfaces[0](0, 0);
	g->Pu[0][1] = mMidSurfaces[0](1, 0);
	g->Pv[0][1] = mMidSurfaces[2](5, 0);
	g->Puv[0][1] = mMidSurfaces[2](5, 0)*2.0f - mMidSurfaces[2](5, 1);
	g->Pvu[0][1] = mMidSurfaces[0](1, 0)*2.0f - mMidSurfaces[0](1, 1);

	g->P[0][0] = mMidSurfaces[2](3, 0);
	g->Pu[0][0] = mBezierCurves[2]->GetPoint(1);
	g->Pv[0][0] = mMidSurfaces[2](4, 0);
	g->Pvu[0][0] = g->Pvu[0][1]*2.0f - (mMidSurfaces[0](1, 1)*2.0f - mMidSurfaces[0](1, 2));
	g->Puv[0][0] = mMidSurfaces[2](4, 0)*2.0f - mMidSurfaces[2](4, 1);

	g->P[1][1] = mMidSurfaces[0](3, 0);
	g->Pu[1][1] = mMidSurfaces[0](2, 0);
	g->Pv[1][1] = mBezierCurves[0]->GetPoint(1);
	g->Pvu[1][1] = mMidSurfaces[0](2, 0)*2.0f - mMidSurfaces[0](2, 1);
	g->Puv[1][1] = g->Puv[0][1]*2.0f - (mMidSurfaces[2](5, 1)*2.0f - mMidSurfaces[2](5, 2));

	g->P[1][0] = mBezierCurves[0]->GetPoint(3);
	g->Pu[1][0] = mBezierCurves[2]->GetPoint(2);
	g->Pv[1][0] = mBezierCurves[0]->GetPoint(2);
	g->Puv[1][0] = g->Puv[0][0]*2.0f - (mMidSurfaces[2](4, 1)*2.0f - mMidSurfaces[2](4, 2));
	g->Pvu[1][0] = g->Pvu[1][1]*2.0f - (mMidSurfaces[0](2, 1)*2.0f - mMidSurfaces[0](2, 2));

	g->BezierToHermite();
	g->ChangeU(mGregoryPrecision);
	mGregorySurfaces[0] = g;


	// second mGregorySurfaces patch
	g = new GregorySurface();
	g->P[1][1] = mMidSurfaces[0](6, 0);
	g->Pu[1][1] = mMidSurfaces[0](5, 0);
	g->Pv[1][1] = mMidSurfaces[1](1, 0);
	g->Pvu[1][1] = mMidSurfaces[0](5, 0)*2.0f - mMidSurfaces[0](5, 1);
	g->Puv[1][1] = mMidSurfaces[1](1, 0)*2.0f - mMidSurfaces[1](1, 1);

	g->P[0][1] = mMidSurfaces[0](3, 0);
	g->Pu[0][1] = mMidSurfaces[0](4, 0);
	g->Pv[0][1] = mBezierCurves[0]->GetPoint(1);
	g->Pvu[0][1] = mMidSurfaces[0](4, 0)*2.0f - mMidSurfaces[0](4, 1);
	g->Puv[0][1] = g->Puv[1][1]*2.0f - (mMidSurfaces[1](1, 1)*2.0f - mMidSurfaces[1](1, 2));

	g->P[1][0] = mMidSurfaces[1](3, 0);
	g->Pu[1][0] = mBezierCurves[1]->GetPoint(1);
	g->Pv[1][0] = mMidSurfaces[1](2, 0);
	g->Puv[1][0] = mMidSurfaces[1](2, 0)*2.0f - mMidSurfaces[1](2, 1);
	g->Pvu[1][0] = g->Pvu[1][1]*2.0f - (mMidSurfaces[0](5, 1)*2.0f - mMidSurfaces[0](5, 2));

	g->P[0][0] = mBezierCurves[0]->GetPoint(3);
	g->Pu[0][0] = mBezierCurves[1]->GetPoint(2);
	g->Pv[0][0] = mBezierCurves[0]->GetPoint(2);
	g->Puv[0][0] = g->Puv[1][0]*2.0f - (mMidSurfaces[1](2, 1)*2.0f - mMidSurfaces[1](2, 2));
	g->Pvu[0][0] = g->Pvu[0][1]*2.0f - (mMidSurfaces[0](4, 1)*2.0f - mMidSurfaces[0](4, 2));

	g->BezierToHermite();
	g->ChangeU(mGregoryPrecision);
	mGregorySurfaces[1] = g;


	// third mGregorySurfaces patch
	g = new GregorySurface();
	g->P[1][0] = mMidSurfaces[2](0, 0);
	g->Pu[1][0] = mMidSurfaces[2](1, 0);
	g->Pv[1][0] = mMidSurfaces[1](5, 0);
	g->Puv[1][0] = mMidSurfaces[1](5, 0)*2.0f - mMidSurfaces[1](5, 1);
	g->Pvu[1][0] = mMidSurfaces[2](1, 0)*2.0f - mMidSurfaces[2](1, 1);

	g->P[0][0] = mMidSurfaces[2](3, 0);
	g->Pu[0][0] = mMidSurfaces[2](2, 0);
	g->Pv[0][0] = mBezierCurves[2]->GetPoint(1);
	g->Pvu[0][0] = mMidSurfaces[2](2, 0)*2.0f - mMidSurfaces[2](2, 1);
	g->Puv[0][0] = g->Puv[1][0]*2.0f - (mMidSurfaces[1](5, 1)*2.0f - mMidSurfaces[1](5, 2));

	g->P[1][1] = mMidSurfaces[1](3, 0);
	g->Pv[1][1] = mMidSurfaces[1](4, 0);
	g->Pu[1][1] = mBezierCurves[1]->GetPoint(1);
	g->Puv[1][1] = mMidSurfaces[1](4, 0)*2.0f - mMidSurfaces[1](4, 1);
	g->Pvu[1][1] = g->Pvu[1][0]*2.0f - (mMidSurfaces[2](1, 1)*2.0f - mMidSurfaces[2](1, 2));

	g->P[0][1] = mBezierCurves[1]->GetPoint(3);
	g->Pu[0][1] = mBezierCurves[1]->GetPoint(2);
	g->Pv[0][1] = mBezierCurves[2]->GetPoint(2);
	g->Puv[0][1] = g->Puv[1][1]*2.0f - (mMidSurfaces[1](4, 1)*2.0f - mMidSurfaces[1](4, 2));
	g->Pvu[0][1] = g->Pvu[0][0]*2.0f - (mMidSurfaces[2](2, 1)*2.0f - mMidSurfaces[2](2, 2));

	g->BezierToHermite();
	g->ChangeU(mGregoryPrecision);
	mGregorySurfaces[2] = g;

	PreventContinuity();
}

cVoid TriGregory::MakeBorderCurves() {
	Point4D a[3], b[3], c[3], d[3], p;

	for (cInt i = 0; i < 3; i++)	{
		a[i] = mMidSurfaces[i](3, 0);
		b[i] = mMidSurfaces[i](3, 0)*2.0f - mMidSurfaces[i](3, 1);
		c[i] = b[i] + (b[i] - a[i])*mCurveParam;
	}
	p = (c[0] + c[1] + c[2])/3.0f;

	for (cInt i = 0; i < 3; i++) {
		d[i] = p + (c[i] - p)*2.0f/3.0f;
	}

	for (cInt i = 0; i < 3; i++) {
		delete mBezierCurves[i];
		mBezierCurves[i] = new BezierCurve();
		mBezierCurves[i]->AddPoint(a[i]);
		mBezierCurves[i]->AddPoint(b[i]);
		mBezierCurves[i]->AddPoint(d[i]);
		mBezierCurves[i]->AddPoint(p);
	}
}

cVoid TriGregory::MakeMidPatch(BezierSurface *patch, DynamicArray2D<Point4D> &out) {
	DynamicArray2D<Point4D> temp(4, 7);
	out = DynamicArray2D<Point4D>(7, 7);

	for (cInt i = 0; i < 4; i++)	{
		temp(i, 0) = patch->GetMeshPoint(i, 0);
		temp(i, 1) = (patch->GetMeshPoint(i, 0) + patch->GetMeshPoint(i, 1))/2;
		temp(i, 3) = (patch->GetMeshPoint(i, 1) + patch->GetMeshPoint(i, 2))/2;
		temp(i, 5) = (patch->GetMeshPoint(i, 2) + patch->GetMeshPoint(i, 3))/2;
		temp(i, 2) = (temp(i,1) + temp(i,3))/2;
		temp(i, 4) = (temp(i,3) + temp(i,5))/2;
		temp(i, 3) = (temp(i,2) + temp(i,4))/2;
		temp(i, 6) = patch->GetMeshPoint(i, 3);
	}

	for (cInt i = 0; i < 7; i++)	{
		out(0, i) = temp(0, i);
		out(1, i) = (temp(0, i) + temp(1, i))/2;
		out(3, i) = (temp(1, i) + temp(2, i))/2;
		out(5, i) = (temp(2, i) + temp(3, i))/2;
		out(2, i) = (out(1, i) + out(3, i))/2;
		out(4, i) = (out(3, i) + out(5, i))/2;
		out(3, i) = (out(2, i) + out(4, i))/2;
		out(6, i) = temp(3, i);
	}
}

cVoid TriGregory::CorrectPatches() {
	Point4D p;
	cInt next;

	for (cInt k = 0; k < 3; k++) {
		for (cInt i = 0; i < 4; i++) {
			for (cInt j = 0; j < 4; j++) {
				mBezierSurfaces[k]->UpdateMeshPoint(i, j, mOldSurfaces[k](i, j));
			}
		}
	}

	for (cInt i = 0; i < 3; i++)	{
		next = (i + 1)%3;

		// C0 correction
		mBezierSurfaces[next]->UpdateMeshPoint(0, 0, mBezierSurfaces[i]->GetMeshPoint(3, 0));

		// C1 correction
		if (mContinuity < 1) {
			continue;
		}
		mBezierSurfaces[next]->UpdateMeshPoint(0, 1, mBezierSurfaces[i]->GetMeshPoint(3, 0)*2.0f - mBezierSurfaces[i]->GetMeshPoint(2, 0));
		mBezierSurfaces[i]->UpdateMeshPoint(3, 1, mBezierSurfaces[next]->GetMeshPoint(0, 0)*2.0f - mBezierSurfaces[next]->GetMeshPoint(1, 0));

		// C2 correction with average point
		if (mContinuity < 2) {
			continue;
		}
		p = mBezierSurfaces[next]->GetMeshPoint(0, 1)*2.0f - mBezierSurfaces[next]->GetMeshPoint(1, 1);
		p = p + mBezierSurfaces[i]->GetMeshPoint(3, 1)*2.0f - mBezierSurfaces[i]->GetMeshPoint(2, 1);
		p = p/2.0f;
		mBezierSurfaces[next]->UpdateMeshPoint(1, 1, mBezierSurfaces[next]->GetMeshPoint(0, 1)*2.0f - p);
		mBezierSurfaces[i]->UpdateMeshPoint(2, 1, mBezierSurfaces[i]->GetMeshPoint(3, 1)*2.0f - p);
	}
}

cVoid TriGregory::PreventContinuity() {
	switch (mContinuity)	{
	case 0:
		for (cInt i = 0; i < 3; i++) {
			DeleteMixDeriv(mGregorySurfaces[i], 0, 1, true, true);
			DeleteMixDeriv(mGregorySurfaces[i], 1, 0, true, true);
			DeleteMixDeriv(mGregorySurfaces[i], 1, 1, true, true);
			DeleteMixDeriv(mGregorySurfaces[i], 0, 0, true, true);
		}
		break;
	case 1:
		DeleteMixDeriv(mGregorySurfaces[0], 0, 0, false, true);
		DeleteMixDeriv(mGregorySurfaces[0], 1, 1, true, false);
		DeleteMixDeriv(mGregorySurfaces[0], 1, 0, true, true);

		DeleteMixDeriv(mGregorySurfaces[1], 0, 0, true, true);
		DeleteMixDeriv(mGregorySurfaces[1], 0, 1, true, false);
		DeleteMixDeriv(mGregorySurfaces[1], 1, 0, false, true);

		DeleteMixDeriv(mGregorySurfaces[2], 0, 1, true, true);
		DeleteMixDeriv(mGregorySurfaces[2], 0, 0, true, false);
		DeleteMixDeriv(mGregorySurfaces[2], 1, 1, false, true);
		break;
	case 2:
		break;
	}
}

cVoid TriGregory::DeleteMixDeriv(GregorySurface *g, cInt i, cInt j, cBool u, cBool v) {
	Point4D p = g->Pu[i][j] + g->Pv[i][j] - g->P[i][j];
	if (u) {
		g->Puv[i][j] = p;
	}
	if (v) {
		g->Pvu[i][j] = p;
	}
}